package global

import (
	"context"
	"time"

	"gitee.com/night-tc/gobige/msgdef"
	"gitee.com/night-tc/gobige/msgdef/protomsg"
)

type RouteCallBackF = func(msgret *protomsg.RouteMsgSrvRet, err error)

type srvOptionF func(*protomsg.RouteMsgSrvReq)

// 设置消息事务订单号
func SrvSetOrderID(orderid uint64) srvOptionF {
	return func(req *protomsg.RouteMsgSrvReq) {
		req.OrderID = orderid
	}
}

// 设置消息事务前缀
func SrvSetPrefix(prefix string) srvOptionF {
	return func(req *protomsg.RouteMsgSrvReq) { req.Prefix = prefix }
}

// 设置消息的处理的角色ID
func SrvSetPID(pid uint64) srvOptionF {
	return func(req *protomsg.RouteMsgSrvReq) { req.PID = pid }
}

// 设置消息处理的实体ID
func SrvSetEID(spid, eid uint64) srvOptionF {
	return func(req *protomsg.RouteMsgSrvReq) {
		req.EntityID = eid
		req.SpaceID = spid
	}
}

// 设置是否需要回复客户端
func SrvSetIsRetClient(v bool) srvOptionF {
	return func(req *protomsg.RouteMsgSrvReq) { req.IsRetClient = v }
}

// 异步请求别的服务器事务，设置回复消息
func PostSrvAsync(
	srvid uint64, msg msgdef.IMsg,
	fcall RouteCallBackF,
	options ...srvOptionF,
) {

	srvreq := new(protomsg.RouteMsgSrvReq)
	srvreq.SourceSrvID = GetCfgInst().GetServerID()
	srvreq.MsgName = msg.Name()
	srvreq.MsgData, _ = msg.Marshal()
	srvreq.BackKey = GetSrvInst().GetNewEID()

	for _, opt := range options {
		opt(srvreq)
	}

	GetSrvInst().GetThreadGo().Go(func(ctx context.Context) {
		select {
		case <-ctx.Done():
			return
		default:
		}
		a, b := PostSrvSyncByRouteReq(srvid, srvreq)
		if fcall != nil {
			fcall(a, b)
		}
	})
}

// 同步请求别的服务器事务
func PostSrvSync(
	srvid uint64, msg msgdef.IMsg,
	options ...srvOptionF,
) (result *protomsg.RouteMsgSrvRet, err error) {
	srvreq := new(protomsg.RouteMsgSrvReq)
	srvreq.SourceSrvID = GetCfgInst().GetServerID()
	srvreq.MsgName = msg.Name()
	srvreq.MsgData, _ = msg.Marshal()
	srvreq.BackKey = GetSrvInst().GetNewEID()

	for _, opt := range options {
		opt(srvreq)
	}
	return PostSrvSyncByRouteReq(srvid, srvreq)
}

// 请求其他服务器消息，不等回复，也不需要处理
func PostSrv(
	srvid uint64, msg msgdef.IMsg,
	options ...srvOptionF,
) error {
	srvreq := new(protomsg.RouteMsgSrvReq)
	srvreq.SourceSrvID = GetCfgInst().GetServerID()
	srvreq.MsgName = msg.Name()
	srvreq.MsgData, _ = msg.Marshal()
	srvreq.BackKey = 0

	for _, opt := range options {
		opt(srvreq)
	}

	GetSrvInst().PostSess(srvid, srvreq)
	return nil
}

func PostSrvSyncByRouteReq(srvid uint64, srvreq *protomsg.RouteMsgSrvReq) (result *protomsg.RouteMsgSrvRet, err error) {
	Chan := make(chan *protomsg.RouteMsgSrvRet, 1)
	GetSrvInst().GetWaitMap().Store(srvreq.BackKey, Chan)
	GetSrvInst().PostSess(srvid, srvreq)

	tk := time.NewTimer(5 * time.Second)
	defer tk.Stop()
	select {
	case <-tk.C:
		GetSrvInst().GetWaitMap().LoadAndDelete(srvreq.BackKey)
		return nil, Err_TimeOut
	case result = <-Chan:
		return result, nil
	}
}
